Hoe komt het dat bepaalde willekeurige tekenreeksen kleuren produceren wanneer ze als achtergrondkleuren in HTML worden ingevoerd? Bijvoorbeeld: test ... produceert een document met een rode achtergrond in alle browsers en platforms. Interessant is dat terwijl chucknorri ook een rode achtergrond produceert, chucknorr een gele achtergrond produceert. Wat is hier aan de hand?
2020-12-07 21:55:48
Het is een overblijfsel uit de Netscape-dagen: Ontbrekende cijfers worden behandeld als 0 [...]. Een onjuist cijfer wordt simpelweg geïnterpreteerd als 0. De waarden # F0F0F0, F0F0F0, F0F0F, #FxFxFx en FxFxFx zijn bijvoorbeeld allemaal hetzelfde. Het komt uit de blogpost Een beetje tirade over de kleurparsering van Microsoft Internet Explorer, die het tot in detail behandelt, inclusief verschillende lengtes van kleurwaarden, enz. Als we de regels uit de blogpost beurtelings toepassen, krijgen we het volgende: Vervang alle ongeldige hexadecimale tekens door nullen: chucknorris wordt c00c0000000 Ga naar het volgende totale aantal tekens dat deelbaar is door 3 (11 → 12): c00c 0000 0000 Opgesplitst in drie gelijke groepen, waarbij elke component de overeenkomstige kleurcomponent van een RGB-kleur vertegenwoordigt: RGB (c00c, 0000, 0000) Breek elk van de argumenten van rechts af tot twee tekens. Wat tenslotte het volgende resultaat geeft: RGB (c0, 00, 00) = # C00000 of RGB (192, 0, 0) Hier is een voorbeeld dat het attribuut bgcolor in actie laat zien, om dit "verbazingwekkende" kleurstaal te produceren:chuck norris Meneer T ninjaturtle Dit beantwoordt ook het andere deel van de vraag: waarom produceert bgcolor = "chucknorr" een gele kleur? Als we de regels toepassen, is de string: c00c00000 => c00 c00 000 => c0 c0 00 [RGB (192, 192, 0)] Wat een lichtgele gouden kleur geeft. Aangezien de tekenreeks begint met 9 tekens, behouden we deze keer de tweede ‘C’, waardoor het eindigt in de uiteindelijke kleurwaarde. Ik kwam dit oorspronkelijk tegen toen iemand erop wees dat je color = "crap" kon doen en, nou ja, het komt er bruin uit. | Het spijt me dat ik het niet eens ben, maar volgens de regels voor het parseren van een oude kleurwaarde die is gepost door @Yuhong Bao, is chucknorris NIET gelijk aan # CC0000, maar eerder aan # C00000, een zeer vergelijkbare maar iets andere tint rood. Ik heb de Firefox ColorZilla-add-on gebruikt om dit te verifiëren. De regels stellen: maak de string een lengte die een veelvoud is van 3 door 0s toe te voegen: chucknorris0 verdeel de snaar in 3 strings van gelijke lengte: chuc knor ris0 afkappen elke string tot 2 karakters: ch kn ri bewaar de hexadecimale waarden en voeg waar nodig nullen toe: C0 00 00 Ik kon deze regels gebruiken om de volgende strings correct te interpreteren: LuckyCharms Geluk LuckBeALady LuckBeALadyTonight Gangnam stijl BIJWERKEN: De oorspronkelijke antwoordenden die zeiden dat de kleur # CC0000 was, hebben sindsdien hun antwoorden bewerkt om de correctie op te nemen. | De meeste browsers negeren gewoon alle NIET-hexadecimale waarden in uw kleurstring en vervangen niet-hexadecimale cijfers door nullen. ChuCknorris vertaalt naar c00c0000000. Op dit punt zal de browser de string in drie gelijke secties verdelen, waarbij de waarden Rood, Groen en Blauw worden aangegeven: c00c 0000 0000. Extra bits in elke sectie worden genegeerd, waardoor het uiteindelijke resultaat # c00000 een roodachtige kleur heeft. Let op, dit is niet van toepassing op CSS-kleurparsing, die de CSS-standaard volgen. ziek onzin gras Roodachtig
Hetzelfde als hierboven
Zwart
| De reden is dat de browser het niet kan begrijpen en probeert het op de een of andere manier te vertalen naar wat het kan begrijpen en in dit geval naar een hexadecimale waarde! ... chucknorris begint met c, dat wordt herkend in hexadecimaal teken, en het converteert ook alle niet-herkende tekens naar 0! Dus chucknorris in hexadecimaal formaat wordt: c00c00000000, alle andere karakters worden 0 en c blijft waar ze zijn ... Nu worden ze gedeeld door 3 voor RGB (rood, groen, blauw) ... R: c00c, G: 0000, B: 0000 ... Maar we weten dat een geldig hexadecimaal voor RGB slechts 2 tekens is, wat betekent dat R: c0, G: 00, B: 00 Het echte resultaat is dus: bgcolor = "# c00000"; Ik heb ook de stappen in de afbeelding toegevoegd als een snelle referentie voor je: | De browser probeert chucknorris om te zetten in hexadecimale kleurcode, omdat het geen geldige waarde is. In chucknorris is alles behalve c geen geldige hexadecimale waarde. Dus het wordt geconverteerd naar c00c00000000. Dat wordt # c00000, een rode tint. Dit lijkt voornamelijk een probleem te zijn met Internet Explorer en Opera (12), aangezien zowel Chrome (31) als Firefox (26) dit gewoon negeren. P.S. De cijfers tussen haakjes zijn de browserversies waarop ik heb getest. Op een lichtere toon Chuck Norris voldoet niet aan webstandaarden. Webstandaarden voldoen naar hem. # BADA55 | De WHATWG HTML-specificatie heeft het exacte algoritme voor het parseren van een oude kleurwaarde: https://html.spec.whatwg.org/multipage/infrastructure.html#rules-for-parsing-a-legacy-colour-value. De code die Netscape Classic gebruikt voor het ontleden van kleurstrings is open source: https://dxr.mozilla.org/classic/source/lib/layout/layimage.c#155. Merk bijvoorbeeld op dat elk teken wordt geparseerd als een hexadecimaal cijfer en vervolgens wordt verschoven naar een 32-bits geheel getal zonder te controleren op overflow. Slechts acht hexadecimale cijfers passen in een 32-bits geheel getal, daarom worden alleen de laatste 8 tekens in aanmerking genomen. Na het ontleden van de hexadecimale cijfers in 32-bits gehele getallen, worden ze vervolgens afgekapt in 8-bits gehele getallen door ze te delen door 16 totdat ze passen in 8-bits. Daarom worden voorloopnullen genegeerd. Update: deze code komt niet exact overeen met wat is gedefinieerd in de specificatie, maar het enige verschil is dat er een paar regels code zijn. Ik denk dat het deze regels zijn die zijn toegevoegd (in Netscape 4): if (bytes_per_val> 4) { bytes_per_val = 4; } | Antwoord: De browser zal proberen om chucknorris om te zetten in een hexadecimale waarde. Aangezien c het enige geldige hexadecimale teken in chucknorris is, verandert de waarde in: c00c00000000 (0 voor alle waarden die ongeldig waren). De browser verdeelt het resultaat vervolgens in 3 groepen: Rood = c00c, Groen = 0000, Blauw = 0000. Aangezien geldige hex-waarden voor html-achtergronden slechts 2 cijfers bevatten voor elk kleurtype (r, g, b), worden de laatste 2 cijfers afgekapt uit elke groep, waardoor een rgb-waarde van c00000 overblijft, wat een steenroodachtige kleur is. | chucknorris begint met c en de browser leest het in een hexadecimale waarde. Omdat A, B, C, D, E en F tekens in hexadecimaal zijn. De browser converteert chucknorris naar een hexadecimale waarde, C00C00000000. Vervolgens wordt de hexadecimale waarde C00C00000000 geconverteerd naar RGB-indeling (gedeeld door 3): C00C00000000 ⇒ R: C00C, G: 0000, B: 0000 De browser heeft slechts twee cijfers nodig om de kleur aan te geven: R: C00C, G: 0000, B: 0000 ⇒ R: C0, G: 00, B: 00 ⇒ C00000 Toon tenslotte bgcolor = C00000 in de webbrowser. Hier is een voorbeeld dat het laat zien:| De regels voor het parseren van kleuren op verouderde attributen omvatten extra stappen dan die vermeld in bestaande antwoorden. Het onderdeel afkappen tot 2 cijfers wordt beschreven als: Gooi alle karakters weg behalve de laatste 8 Gooi voorloopnullen een voor een weg, zolang alle componenten een voorloopnul hebben Gooi alle karakters weg behalve de eerste 2 Een paar voorbeelden: oooFoooFoooF 000F 000F 000F <- vervang, pad en brok 0F 0F 0F <- voorloopnullen afgekapt 0F 0F 0F <- afgekapt tot 2 tekens van rechts oooFooFFoFFF 000F 00FF 0FFF <- vervang, pad en brok 00F 0FF FFF <- voorloopnullen afgekapt 00 0F FF <- afgekapt tot 2 tekens van rechts ABCooooooABCooooooABCoooooo ABC000000 ABC000000 ABC000000 <- vervang, pad en brok BC000000 BC000000 BC000000 <- afgekapt tot 8 tekens van links BC BC BC <- afgekapt tot 2 tekens van rechts AoCooooooAoCooooooAoCoooooo A0C000000 A0C000000 A0C000000 <- vervangen, pad en brok 0C000000 0C000000 0C000000 <- afgekapt tot 8 tekens van links C000000 C000000 C000000 <- voorloopnullen afgekapt C0 C0 C0 <- ingekort tot 2 tekens van rechts Hieronder vindt u een gedeeltelijke implementatie van het algoritme. Het behandelt geen fouten of gevallen waarin de gebruiker een geldige kleur invoert. functie parseColor (invoer) { // todo: retourneer fout als invoer "" is input = input.trim (); // todo: retourneer fout als invoer "transparant" is // todo: retourneer overeenkomstige #rrggbb als invoer een benoemde kleur is // todo: retourneer #rrggbb als de invoer overeenkomt met #rgb // todo: vervang unicode-codepunten groter dan U + FFFF door 00 if (input.length> 128) { input = input.slice (0, 128); } if (input.charAt (0) === "#") { input = input.slice (1); } input = input.replace (/ [^ 0-9A-Fa-f] / g, "0"); while (input.length === 0 || input.length% 3> 0) { input + = "0"; } var r = input.slice (0, input.length / 3); var g = input.slice (input.length / 3, input.length * 2/3); var b = input.slice (input.length * 2/3); if (r.length> 8) { r = r.slice (-8); g = g.schijf (-8); b = b.stuk (-8); } while (r.length> 2 && r.charAt (0) === "0" && g.charAt (0) === "0" && b.charAt (0) === "0") { r = r.stuk (1); g = g.schijf (1); b = b.stuk (1); } if (r.length> 2) { r = r.stuk (0, 2); g = g. plak (0, 2); b = b.stuk (0, 2); } return "#" + r.padStart (2, "0") + g.padStart (2, "0") + b.padStart (2, "0"); } $ (functie () { $ ("# input"). on ("change", function () { var input = $ (this) .val (); var color = parseColor (invoer); var $ cells = $ ("# resultaat tbody td"); $ cells.eq (0) .attr ("bgcolor", invoer); $ cells.eq (1) .attr ("bgcolor", kleur); varwaarde: https://html.spec.whatwg.org/multipage/infrastructure.html#rules-for-parsing-a-legacy-colour-value. De code die Netscape Classic gebruikt voor het ontleden van kleurstrings is open source: https://dxr.mozilla.org/classic/source/lib/layout/layimage.c#155. Merk bijvoorbeeld op dat elk teken wordt geparseerd als een hexadecimaal cijfer en vervolgens wordt verschoven naar een 32-bits geheel getal zonder te controleren op overflow. Slechts acht hexadecimale cijfers passen in een 32-bits geheel getal, daarom worden alleen de laatste 8 tekens in aanmerking genomen. Na het ontleden van de hexadecimale cijfers in 32-bits gehele getallen, worden ze vervolgens afgekapt in 8-bits gehele getallen door ze te delen door 16 totdat ze passen in 8-bits. Daarom worden voorloopnullen genegeerd. Update: deze code komt niet exact overeen met wat is gedefinieerd in de specificatie, maar het enige verschil is dat er een paar regels code zijn. Ik denk dat het deze regels zijn die zijn toegevoegd (in Netscape 4): if (bytes_per_val> 4) { bytes_per_val = 4; } | Antwoord: De browser zal proberen om chucknorris om te zetten in een hexadecimale waarde. Aangezien c het enige geldige hexadecimale teken in chucknorris is, verandert de waarde in: c00c00000000 (0 voor alle waarden die ongeldig waren). De browser verdeelt het resultaat vervolgens in 3 groepen: Rood = c00c, Groen = 0000, Blauw = 0000. Aangezien geldige hex-waarden voor html-achtergronden slechts 2 cijfers bevatten voor elk kleurtype (r, g, b), worden de laatste 2 cijfers afgekapt uit elke groep, waardoor een rgb-waarde van c00000 overblijft, wat een steenroodachtige kleur is. | chucknorris begint met c en de browser leest het in een hexadecimale waarde. Omdat A, B, C, D, E en F tekens in hexadecimaal zijn. De browser converteert chucknorris naar een hexadecimale waarde, C00C00000000. Vervolgens wordt de hexadecimale waarde C00C00000000 geconverteerd naar RGB-indeling (gedeeld door 3): C00C00000000 ⇒ R: C00C, G: 0000, B: 0000 De browser heeft slechts twee cijfers nodig om de kleur aan te geven: R: C00C, G: 0000, B: 0000 ⇒ R: C0, G: 00, B: 00 ⇒ C00000 Toon tenslotte bgcolor = C00000 in de webbrowser. Hier is een voorbeeld dat het laat zien: chucknorris c00c00000000 c00000 | De regels voor het parseren van kleuren op verouderde attributen omvatten extra stappen dan die vermeld in bestaande antwoorden. Het onderdeel afkappen tot 2 cijfers wordt beschreven als: Gooi alle karakters weg behalve de laatste 8 Gooi voorloopnullen een voor een weg, zolang alle componenten een voorloopnul hebben Gooi alle karakters weg behalve de eerste 2 Een paar voorbeelden: oooFoooFoooF 000F 000F 000F <- vervang, pad en brok 0F 0F 0F <- voorloopnullen afgekapt 0F 0F 0F <- afgekapt tot 2 tekens van rechts oooFooFFoFFF 000F 00FF 0FFF <- vervang, pad en brok 00F 0FF FFF <- voorloopnullen afgekapt 00 0F FF <- afgekapt tot 2 tekens van rechts ABCooooooABCooooooABCoooooo ABC000000 ABC000000 ABC000000 <- vervang, pad en brok BC000000 BC000000 BC000000 <- afgekapt tot 8 tekens van links BC BC BC <- afgekapt tot 2 tekens van rechts AoCooooooAoCooooooAoCoooooo A0C000000 A0C000000 A0C000000 <- vervangen, pad en brok 0C000000 0C000000 0C000000 <- afgekapt tot 8 tekens van links C000000 C000000 C000000 <- voorloopnullen afgekapt C0 C0 C0 <- ingekort tot 2 tekens van rechts Hieronder vindt u een gedeeltelijke implementatie van het algoritme. Het behandelt geen fouten of gevallen waarin de gebruiker een geldige kleur invoert. functie parseColor (invoer) { // todo: retourneer fout als invoer "" is input = input.trim (); // todo: retourneer fout als invoer "transparant" is // todo: retourneer overeenkomstige #rrggbb als invoer een benoemde kleur is // todo: retourneer #rrggbb als de invoer overeenkomt met #rgb // todo: vervang unicode-codepunten groter dan U + FFFF door 00 if (input.length> 128) { input = input.slice (0, 128); } if (input.charAt (0) === "#") { input = input.slice (1); } input = input.replace (/ [^ 0-9A-Fa-f] / g, "0"); while (input.length === 0 || input.length% 3> 0) { input + = "0"; } var r = input.slice (0, input.length / 3); var g = input.slice (input.length / 3, input.length * 2/3); var b = input.slice (input.length * 2/3); if (r.length> 8) { r = r.slice (-8); g = g.schijf (-8); b = b.stuk (-8); } while (r.length> 2 && r.charAt (0) === "0" && g.charAt (0) === "0" && b.charAt (0) === "0") { r = r.stuk (1); g = g.schijf (1); b = b.stuk (1); } if (r.length> 2) { r = r.stuk (0, 2); g = g. plak (0, 2); b = b.stuk (0, 2); } return "#" + r.padStart (2, "0") + g.padStart (2, "0") + b.padStart (2, "0"); } $ (functie () { $ ("# input"). on ("change", function () { var input = $ (this) .val (); var color = parseColor (invoer); var $ cells = $ ("# resultaat tbody td"); $ cells.eq (0) .attr ("bgcolor", invoer); $ cells.eq (1) .attr ("bgcolor", kleur); var chucknorris c00c00000000 c00000